#ifndef NET_COMMON_H
#define NET_COMMON_H

#include <string.h>
#include <events/sf_assert.h>
#include <util/net_buffer.h>

enum
{
    OP_CURL_STATUS_LOAD_ALL_OVER,      // 表示数据下载全部一次性返回了, data = (NetBuffer *)
    OP_CURL_STATUS_LOAD_ONE_FRAME,     // 表示数据下载方式按照块来计算，有多少数据就来多少 data = (NetBuffer *)
    OP_CURL_STATUS_LOAD_OVER,          // 表示数据下载完成了，与上一个枚举配合，表示下载已经完成，可以关闭文件。 data = not used
    OP_CURL_STATUS_PROGRESS,           // 表示下载进度信息

    OP_CURL_STATUS_ERROR_TYPE,         // 往下的枚举表示数据下载过程中curl的错误定义值, data = (char *)

};
typedef void (*OpCurlStatus) (int status, void *data, void *arg);

/**
  "User-Agent:  Mozilla/5.0 (Windows NT 10.0; Win64; x64)
                AppleWebKit/537.36 (KHTML, like Gecko)
                Chrome/76.0.3809.132
                Safari/537.36"

有时候发出的https GET/POST 消息不会收到信息，但是数据都是对的，这有时需要在http的协议头上，加上user-agent
*/
#ifndef USER_AGENT_STRING
//#define USER_AGENT_STRING "Chrome/76.0.3809.132"
#define USER_AGENT_STRING "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
#endif

class CurlLoadItem;
class CurlLoadArg
{
public:
    class LoadProxy
    {
    public:
        enum AUTH
        {
            AUTH_FOR_YT, // youtube 第一种认证方式
        };
        enum TYPE
        {
            SOCKS5,
        };
        LoadProxy(uint16_t port, const char *svrAddr)
            : proxyAuth(AUTH_FOR_YT)
            , proxyPort(port)
            , proxyType(SOCKS5)
            , proxySVRAddr(svrAddr)
            , proxyUserPwd(NULL)
        {}

        uint32_t    proxyAuth;     // 代理认证模式、
        uint16_t    proxyPort;     // 代理服务器端口
        uint32_t    proxyType;     // 代理类型
        const char *proxySVRAddr;  // 代理服务器地址
        const char *proxyUserPwd;  // http代理认证帐号，名称:pwd的格式, 默认为空
    };

    CurlLoadArg()
        : mUserAgent(0)
        , mReferer(0)
        , mProxy(NULL)
    {}
    CurlLoadArg(const char *agent, const char *ref, LoadProxy *proxy = NULL)
        : mUserAgent(agent)
        , mReferer(ref)
        , mProxy(proxy)
    {}

    const char *userAgent()
    {
        return  mUserAgent;
    }
    void setUserAgent(const char *userAgent)
    {
        mUserAgent = userAgent;
    }

    const char *referer()
    {
        return mReferer;
    }
    void setReferer(const char *ref)
    {
        mReferer = ref;
    }

    LoadProxy *proxy()
    {
        return mProxy;
    }
    void setProxy(LoadProxy *proxy)
    {
        mProxy = proxy;
    }

private:
    const char *mUserAgent;
    const char *mReferer;
    LoadProxy  *mProxy;
};

#include "cJSON.h"
#include <stdarg.h>
using namespace sfcjson;

inline static cJSON *json_items_proc(cJSON *item, const char *name, ...)
{
    cJSON *obj = item;
    va_list args;

    va_start (args, name);
    for (const char *arg = name; arg; arg = va_arg (args, const char *))
    {
        obj = cJSON_GetObjectItem(obj, arg);
        if (!obj)
        {
            // GEN_Printf(LOG_WARN, "json section: %s is null", arg);
        }
    }

    va_end (args);
    return obj;
}

// 交换json内存
#define JSON_VALUETRING_SWAP_BYTESTRING(parent, name, proc) \
    do { \
        cJSON *obj = cJSON_GetObjectItem(parent, #name); \
        if(obj) \
        { \
            proc = obj->valuestring; \
            obj->valuestring = NULL; \
        } else \
        { \
            proc = ByteString(); \
        } \
    } while(0)

// 获取double值
#define JSON_VALUETRING_GET_DOUBLE(parent, name, proc) \
    do { \
        cJSON *obj = cJSON_GetObjectItem(parent, #name); \
        if(obj) \
        { \
            proc = strtod(obj->valuestring, NULL);  /*obj->valuedouble;*/ \
        } else \
        { \
            proc = 0; \
        } \
    } while(0)

#define JSON_STRING_POINTER_SWAP(json, parent, proc) \
    do { \
        if(json != parent) \
        { \
            proc = json->valuestring; \
            json->valuestring = NULL; \
        } else \
        { \
            proc = ByteString(); \
        } \
    } while(0)

#define ITEMS_PROC_NO_PRINT(item, name, proc) \
    do{ \
        obj = cJSON_GetObjectItem(item, name); \
        if( obj ) \
        {   \
            proc; \
        }else \
        { \
            GEN_Printf(LOG_ERROR, "Item " name " is not exist." ); \
        } \
    }while (0)

#define ITEMS_SUB_PROC(item, name, subname, proc) \
    do{ \
        obj = cJSON_GetObjectItem(item, name); \
        if( obj ) \
        {   \
            obj = cJSON_GetObjectItem(obj, subname); \
            if( obj ){ \
                proc; \
            }else \
            { \
                GEN_Printf(LOG_ERROR, "Item " subname " is not exist." ); \
            } \
        }else \
        { \
            GEN_Printf(LOG_ERROR, "Item " name " is not exist." ); \
        } \
    }while (0)

#define ITEMS_SUB_PROC_NO_IF(item, name, subname, proc) \
    do{ \
        obj = cJSON_GetObjectItem(item, name); \
        if( obj ) \
        {   \
            cJSON *tmp = cJSON_GetObjectItem(obj, subname); \
            if( tmp ){ \
                obj = tmp; \
                proc; \
            }else { \
                proc; \
            } \
        }else \
        { \
            GEN_Printf(LOG_ERROR, "Item " name " is not exist." ); \
        } \
    }while (0)

#define ITEMS_SUB_PROC_NO_PRINT(item, name, subname, proc) \
    do{ \
        obj = cJSON_GetObjectItem(item, name); \
        if( obj ) \
        {   \
            obj = cJSON_GetObjectItem(obj, subname); \
            if( obj ){ \
                proc; \
            }\
        }\
    }while (0)

#endif // NET_COMMON_H
